package com.test.profiler

import collection.mutable

import java.io.Writer
import java.io.IOException
import java.text.DecimalFormat

object FrameStats{
  class FilterFull extends Filter {
    def stop(fs: FrameStats): Boolean = {
      return false
    }
  }

  trait Filter {
    def stop(fs: FrameStats): Boolean
  }
}

class FrameStats {
//  private def execSaveXML(w: Writer, filterBranch: String, groupByMethods: FrameStats, maxHolder: Array[Int], stackLocations: List[String]): Unit = {
//    var l: List[FrameStats] = sortNested
//    for (fs <- l) {
//      var filter: String = filterBranch
//      if (filter != null) {
//        if (fs.location.contains(filter)) {
//          filter = null
//          maxHolder(0) = fs.count
//        }
//      }
//      if (filter == null) {
//        if (!stackLocations.contains(fs.location)) {
//          groupByMethods.recordNestedInvocation(fs.location, fs.count)
//        }
//        writeStats(w, fs, maxHolder(0))
//      }
//      stackLocations.add(fs.location)
//      fs.execSaveXML(w, filter, groupByMethods, maxHolder, stackLocations)
//      stackLocations.remove(stackLocations.size - 1)
//      if (filter == null && !fs.allNested.isEmpty) {
//        w.write("</loc>")
//      }
//    }
//  }

  def getCount: Int = {
    return count
  }
  var allNested = new mutable.HashMap[String, FrameStats]

  private def print(w: Writer, nestLevel: Int, filter: FrameStats.Filter): Unit = {
    var l: List[FrameStats] = sortNested
    for (fs <- l) {
      println(w, nestLevel, wrapBold("%-4d..%s".format(fs.count, fs.location), fs.allNested.isEmpty))
      if (!filter.stop(fs)) {
        fs.print(w, nestLevel + 1, filter)
      }
    }
  }

  private def sortNested: List[FrameStats] = {
    allNested.values.toList.sortBy( - _.count )
  }

  private def recordNestedInvocation(location: String, increment: Int): FrameStats = {
    val nested = allNested.getOrElseUpdate(location, {
      val nested = new FrameStats
      nested.location = location
      nested.depth = this.depth + 1
      nested
    })

    nested.count += increment
    return nested
  }
  var depth: Int = 1

  private def println(w: Writer, nestLevel: Int, text: String): Unit = {

    {
      var i: Int = 0
      while (i < nestLevel) {
        {
          w.write('|')
          w.write(' ')
        }
        ({i += 1; i})
      }
    }
    w.write(text + "\n")
  }
  def collectHotSpots(m: mutable.HashMap[String,Long]): Unit = {
    m.update(location, m.getOrElse(location,0L)+count)
    for (n <- allNested.values) {
      n.collectHotSpots(m)
    }
  }
  def wrapBold(s: String, wrap: Boolean): String = {
    if (!wrap) return s
    return "<b>" + s + "</b>"
  }

  private def writeStats(w: Writer, fs: FrameStats, max: Double): Unit = {
    var df: DecimalFormat = new DecimalFormat
    df.setMaximumFractionDigits(1)
    var perc: Double = fs.count / max * 100
    w.write("\r\n")

    {
      var i: Int = 0
      while (i < depth) {
        {
          w.write(' ')
        }
        ({i += 1; i})
      }
    }
    w.write("<loc l='" + df.format(perc) + "%  " + fs.location.replaceAll("<init>", "&lt;init&gt;") + "'")
    if (fs.allNested.isEmpty) {
      w.write("/>")
    }
    else {
      w.write(">")
    }
  }

  def recordNestedInvocation(location: String): FrameStats = {
    return recordNestedInvocation(location, 1)
  }
  var count: Int = 0

  def print(w: Writer, filter: FrameStats.Filter): Unit = {
    print(w, 0, filter)
  }
//  def saveXML(w: Writer, filterBranch: String): Unit = {
//    var groupByMethods: FrameStats = new FrameStats
//    w.write("\r\n<root>")
//    var maxHolder: Array[Int] = Array[Int](0)
//    w.write("\r\n<tree>")
//    execSaveXML(w, filterBranch, groupByMethods, maxHolder, new ArrayList[String])
//    w.write("\r\n</tree>")
//    w.write("\r\n<methods>")
//    var l: List[FrameStats] = groupByMethods.sortNested
//    for (fs <- l) {
//      writeStats(w, fs, maxHolder(0))
//    }
//    w.write("\r\n</methods>")
//    w.write("\r\n</root>")
//  }
  var location: String = ""
  def collectHotSpotsNoNest(m: mutable.Map[String,Long]): Unit = {
    var countNested: Long = 0
    for (n <- allNested.values) {
      countNested += n.getCount
      n.collectHotSpotsNoNest(m)
    }
    val diff:Long = count - countNested
    val oldVal:Long = m.getOrElse(location, 0)
    val newVal:Long = oldVal + diff
    m.update(location, newVal)
    //m.increment(location, count - countNested)
  }
}

